/*********************************************************************
 * Copyright (C) 2006 Andrew Khan
 * <p>
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * <p>
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * <p>
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 ***************************************************************************/

package jxl.biff.drawing;

import java.io.File;
import java.io.FileInputStream;
import java.util.Arrays;

public class PNGReader {
    private byte[] pngData;

    private Chunk ihdr;
    private Chunk phys;

    private int pixelWidth;
    private int pixelHeight;
    private int verticalResolution;
    private int horizontalResolution;
    private int resolutionUnit;

    private static byte[] PNG_MAGIC_NUMBER = new byte[]
            {(byte) 0x89, (byte) 0x50, (byte) 0x4e, (byte) 0x47,
                    (byte) 0x0d, (byte) 0x0a, (byte) 0x1a, (byte) 0x0a};

    public PNGReader(byte[] data) {
        pngData = data;
    }

    void read() {
        // Verify the magic data
        byte[] header = new byte[PNG_MAGIC_NUMBER.length];
        System.arraycopy(pngData, 0, header, 0, header.length);
        boolean pngFile = Arrays.equals(PNG_MAGIC_NUMBER, header);
        if (!pngFile) {
            return;
        }

        int pos = 8;
        while (pos < pngData.length) {
            int length = getInt(pngData[pos],
                    pngData[pos + 1],
                    pngData[pos + 2],
                    pngData[pos + 3]);
            ChunkType chunkType = ChunkType.getChunkType(pngData[pos + 4],
                    pngData[pos + 5],
                    pngData[pos + 6],
                    pngData[pos + 7]);

            if (chunkType == ChunkType.IHDR) {
                ihdr = new Chunk(pos + 8, length, chunkType, pngData);
            } else if (chunkType == ChunkType.PHYS) {
                phys = new Chunk(pos + 8, length, chunkType, pngData);
            }

            pos += length + 12;
        }

        // Get the width and height from the ihdr
        byte[] ihdrData = ihdr.getData();
        pixelWidth = getInt(ihdrData[0], ihdrData[1], ihdrData[2], ihdrData[3]);
        pixelHeight = getInt(ihdrData[4], ihdrData[5], ihdrData[6], ihdrData[7]);

        if (phys != null) {
            byte[] physData = phys.getData();
            resolutionUnit = physData[8];
            horizontalResolution = getInt(physData[0], physData[1],
                    physData[2], physData[3]);
            verticalResolution = getInt(physData[4], physData[5],
                    physData[6], physData[7]);
        }
    }

    // Gets the big-Endian integer
    private int getInt(byte d1, byte d2, byte d3, byte d4) {
        int i1 = d1 & 0xff;
        int i2 = d2 & 0xff;
        int i3 = d3 & 0xff;
        int i4 = d4 & 0xff;

        int val = i1 << 24 |
                i2 << 16 |
                i3 << 8 |
                i4;

        return val;
    }

    public int getHeight() {
        return pixelHeight;
    }

    public int getWidth() {
        return pixelWidth;
    }

    public int getHorizontalResolution() {
        // only return if the resolution unit is in metres
        return resolutionUnit == 1 ? horizontalResolution : 0;
    }

    public int getVerticalResolution() {
        // only return if the resolution unit is in metres
        return resolutionUnit == 1 ? verticalResolution : 0;
    }

    public static void main(String args[]) {
        try {
            File f = new File(args[0]);
            int size = (int) f.length();

            byte[] data = new byte[size];

            FileInputStream fis = new FileInputStream(f);
            fis.read(data);
            fis.close();
            PNGReader reader = new PNGReader(data);
            reader.read();
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
}
